package cn.infrabase.core.lang;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

/**
 * 常用正则表达式集合，更多正则见：{@code https://any86.github.io/any-rule/}
 *
 * @author Weimin Gao
 * @since 1.0.0
 **/
public class PatternPool {

    private static final ConcurrentHashMap<RegexWithFlag, Pattern> POOL = new ConcurrentHashMap<>();

    /**
     * 英文字母 、数字和下划线
     */
    public final static Pattern GENERAL = Pattern.compile(RegexPool.GENERAL);

    /**
     * 英文字母
     */
    public final static Pattern WORD = Pattern.compile(RegexPool.WORD);

    /**
     * 数字
     */
    public final static Pattern NUMBERS = Pattern.compile(RegexPool.NUMBERS);

    /**
     * 单个中文汉字
     */
    public final static Pattern CHINESE = Pattern.compile(RegexPool.CHINESE);

    /**
     * 中文汉字
     */
    public final static Pattern CHINESES = Pattern.compile(RegexPool.CHINESES);

    /**
     * 分组
     */
    public final static Pattern GROUP_VAR = Pattern.compile(RegexPool.GROUP_VAR);

    /**
     * IPV4
     */
    public final static Pattern IPV4 = Pattern.compile(RegexPool.IPV4);

    /**
     * IPV6
     */
    public final static Pattern IPV6 = Pattern.compile(RegexPool.IPV6);

    /**
     * 货币
     */
    public final static Pattern MONEY = Pattern.compile(RegexPool.MONEY);

    /**
     * 邮件，符合RFC 5322规范，正则来自：{@code http://emailregex.com/}
     */
    public final static Pattern EMAIL = Pattern.compile(RegexPool.EMAIL, Pattern.CASE_INSENSITIVE);

    /**
     * <pre>
     * 中国大陆移动电话
     * 例：+86 180 4953 1399，其中2位区域码标示+13位数字
     * </pre>
     */
    public final static Pattern MOBILE = Pattern.compile(RegexPool.MOBILE);

    /**
     * <pre>
     * 中国香港移动电话
     * 例：+852 5100 4810，其中3位区域码+8位数字，中国香港手机号码8位数
     * </pre>
     */
    public final static Pattern MOBILE_HK = Pattern.compile(RegexPool.MOBILE_HK);

    /**
     * <pre>
     * 中国台湾移动电话
     * 例：+886 09 60 000000，其中3位区域码+号码以数字09开头+8位数字，中国台湾手机号码10位数
     * </pre>
     */
    public final static Pattern MOBILE_TW = Pattern.compile(RegexPool.MOBILE_TW);

    /**
     * <pre>
     * 中国澳门移动电话
     * 例：+853 68 00000，其中3位区域码+号码以数字6开头+7位数字，中国台湾手机号码8位数
     * </pre>
     */
    public final static Pattern MOBILE_MO = Pattern.compile(RegexPool.MOBILE_MO);

    /**
     * 中国大陆座机号码
     */
    public final static Pattern TEL = Pattern.compile(RegexPool.TEL);

    /**
     * 座机号码+400+800电话
     */
    public final static Pattern TEL_400_800 = Pattern.compile(RegexPool.TEL_400_800);

    /**
     * 18位身份证号码
     */
    public final static Pattern CITIZEN_ID = Pattern.compile(RegexPool.CITIZEN_ID);

    /**
     * 邮编，兼容港澳台
     */
    public final static Pattern ZIP_CODE = Pattern.compile(RegexPool.ZIP_CODE);

    /**
     * 生日
     */
    public final static Pattern BIRTHDAY = Pattern.compile(RegexPool.BIRTHDAY);

    /**
     * URI，定义见：{@code https://www.ietf.org/rfc/rfc3986.html#appendix-B}
     */
    public final static Pattern URI = Pattern.compile(RegexPool.URI);

    /**
     * URL
     */
    public final static Pattern URL = Pattern.compile(RegexPool.URL);

    /**
     * Http URL
     */
    public final static Pattern URL_HTTP = Pattern.compile(RegexPool.URL_HTTP, Pattern.CASE_INSENSITIVE);

    /**
     * 中文字、英文字母、数字和下划线
     */
    public final static Pattern GENERAL_WITH_CHINESE = Pattern.compile(RegexPool.GENERAL_WITH_CHINESE);

    /**
     * UUID
     */
    public final static Pattern UUID = Pattern.compile(RegexPool.UUID, Pattern.CASE_INSENSITIVE);

    /**
     * 不带横线的UUID
     */
    public final static Pattern UUID_SIMPLE = Pattern.compile(RegexPool.UUID_SIMPLE);

    /**
     * MAC地址正则
     */
    public static final Pattern MAC_ADDRESS = Pattern.compile(RegexPool.MAC_ADDRESS, Pattern.CASE_INSENSITIVE);

    /**
     * 16进制字符串
     */
    public static final Pattern HEX = Pattern.compile(RegexPool.HEX);

    /**
     * 时间正则
     */
    public static final Pattern TIME = Pattern.compile(RegexPool.TIME);

    /**
     * 中国车牌号码（兼容新能源车牌）
     */
    public final static Pattern PLATE_NUMBER = Pattern.compile(RegexPool.PLATE_NUMBER);

    /**
     * <pre>
     * 统一社会信用代码
     * 说明：
     * 1、第一部分：登记管理部门代码1位 (数字或大写英文字母)
     * 2、第二部分：机构类别代码1位 (数字或大写英文字母)
     * 3、第三部分：登记管理机关行政区划码6位 (数字)
     * 4、第四部分：主体标识码（组织机构代码）9位 (数字或大写英文字母)
     * 5、第五部分：校验码1位 (数字或大写英文字母)
     * </pre>
     */
    public static final Pattern CREDIT_CODE = Pattern.compile(RegexPool.CREDIT_CODE);

    /**
     * <pre>
     * 车架号（车辆识别代号、车辆识别码），车辆的唯一标示
     * 例如：
     * 1、LDC613P23A1305189
     * 2、LSJA24U62JG269225
     * </pre>
     */
    public static final Pattern CAR_VIN = Pattern.compile(RegexPool.CAR_VIN);

    /**
     * <pre>
     * 中国驾驶证（驾驶证档案编号、行驶证编号），12位数字字符串
     * 例如：
     * 1、430101758218
     * </pre>
     */
    public static final Pattern CAR_DRIVING_LICENCE = Pattern.compile(RegexPool.CAR_DRIVING_LICENCE);

    /**
     * <pre>
     * 中文姓名
     * ------------------------------------------------------------------------
     * 维吾尔族姓名里面的点是 · 输入法中文状态下，键盘左上角数字1前面的那个符号
     * 错误字符：{@code ．.。．.}
     * 正确维吾尔族姓名：
     * 霍加阿卜杜拉·麦提喀斯木
     * 玛合萨提别克·哈斯木别克
     * 阿布都热依木江·艾斯卡尔
     * 阿卜杜尼亚孜·毛力尼亚孜
     * ------------------------------------------------------------------------
     * 错误示例：孟  伟，原因：有空格
     * 错误示例：连逍遥0，原因：有数字
     * 错误示例：依帕古丽-艾则孜，原因：有特殊符号
     * 错误示例：牙力空.买提萨力，原因：新疆人的点不对
     * 错误示例：王建鹏2002-3-2，原因：有数字、特殊符号
     * 错误示例：雷金默(雷皓添），原因：有括号
     * 错误示例：翟冬:亮，原因：有特殊符号
     * 错误示例：李，原因：少于2位
     * ------------------------------------------------------------------------
     * 总结中文姓名：2-60位，只能是中文和维吾尔族的点·
     * 放宽汉字范围：如生僻姓名刘欣䶮yǎn
     * </pre>
     */
    public static final Pattern CHINESE_NAME = Pattern.compile(RegexPool.CHINESE_NAME);


    /**
     * 先从正则缓存池中查找正则匹配模式对象，如果找不到则编译正则表达式并加入正则缓存池。
     *
     * @param regex 正则表达式。
     * @param flags 正则标识位。
     * @return 正则匹配模式对象。
     */
    public static Pattern get(String regex, int flags) {
        final RegexWithFlag regexWithFlag = new RegexWithFlag(regex, flags);
        return POOL.computeIfAbsent(regexWithFlag, (key) -> Pattern.compile(regex, flags));
    }

    /**
     * 先从正则缓存池中查找正则匹配模式对象，如果找不到则编译正则表达式并加入正则缓存池。
     *
     * @param regex 正则表达式。
     * @return 正则匹配模式对象。
     */
    public static Pattern get(String regex) {
        return get(regex, 0);
    }

    /**
     * 移除正则匹配模式对象缓存。
     *
     * @param regex 正则表达式。
     * @param flags 正则标识位。
     * @return 移除的正则匹配模式对象，可能为null值。
     */
    public static Pattern remove(String regex, int flags) {
        return POOL.remove(new RegexWithFlag(regex, flags));
    }

    /**
     * 清空正则匹配模式对象缓存池。
     */
    public static void clear() {
        POOL.clear();
    }

    // -----------------------------------------------------------------------------------------------------------------4

    /**
     * 正则表达式和正则标识位的包装类。
     */
    private static class RegexWithFlag {

		private final String regex;

		private final int flag;

		public RegexWithFlag(String regex,int flag){
			this.regex = regex;
			this.flag = flag;
		}

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            RegexWithFlag that = (RegexWithFlag) o;
            return flag == that.flag && regex.equals(that.regex);
        }

        @Override
        public int hashCode() {
            return Objects.hash(regex, flag);
        }
    }
}
